package com.rpc.server;

import com.esotericsoftware.reflectasm.MethodAccess;
import com.rpc.demo.TestServiceImpl;
import com.rpc.transport.RequestData;
import com.rpc.transport.ResponseData;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.util.concurrent.ConcurrentHashMap;

class ServerHandler extends SimpleChannelInboundHandler<RequestData> {

    private ConcurrentHashMap<String, MethodAccess> concurrentHashMap = new ConcurrentHashMap<>();

    /**
     * 读取客户端发送的数据
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RequestData msg) throws Exception {
        ResponseData responseData   = new ResponseData();
        String       className      = msg.getClassName();
        String       methodName     = msg.getMethodName();
        Class[]      parameterTypes = msg.getParameterTypes();
        Object[]     args           = msg.getArgs();
        Class        interfaceClass = Class.forName(className);
        responseData.setRequestId(msg.getRequestId());

        //TODO:没有区分版本号
        MethodAccess methodAccess = null;
        if (!concurrentHashMap.contains(className)) {
            methodAccess = MethodAccess.get(interfaceClass);
            concurrentHashMap.putIfAbsent(className, methodAccess);
        } else {
            methodAccess = concurrentHashMap.get(className);
        }

        //要找到接口和实现类的对应关系
        //TODO:貌似该反射库没有办法反射以基本类型为参数的方法 所以需要排查下是否是本身实现有问题
        Object object =
                methodAccess.invoke(new TestServiceImpl(), methodName, parameterTypes, args);
        responseData.setResponseData(object);
        ctx.channel().writeAndFlush(responseData);
    }

    /**
     * 客户端连接
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("channelActive");
    }

    /**
     * 客户端断开
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println("channelInactive");
    }

    /**
     * 异常
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        //关闭通道
        ctx.channel().close();
        //打印异常
        cause.printStackTrace();
    }
}